// <editor-fold defaultstate="collapsed" desc="GNU GPLv3 Header">
/*
 * File:   main.c
 *
 * Copyright (C) 2013 Robert Antoni Buj Gelonch <rbuj@uoc.edu>
 * Copyright (C) 2013 David Megias Jimenez <dmegias@uoc.edu>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Created on September 6, 2013, 10:24 AM
 */
// </editor-fold>

#include <stdio.h>
#include <stdlib.h>
#include "WaveDataPCMShort.h"
#include "WaveDataNonPCMByte.h"
#include "AlawEncoder.h"

WaveDataNonPCMByte* PCMSignedToAlaw(WaveDataPCMShort* waveDataIN) {
    int i;
    short int aux;
    WaveDataNonPCMByte* waveDataOUT = malloc(sizeof (WaveDataNonPCMByte));

    // Wave Header
    waveDataOUT->ckHeader = malloc(sizeof (ChunkHeader));
    waveDataOUT->ckHeader->ck = malloc(sizeof (Chunk));
    waveDataOUT->ckHeader->ck->ID = malloc(sizeof (char[5]));
    strcpy(waveDataOUT->ckHeader->ck->ID, "RIFF");
    waveDataOUT->ckHeader->ck->size = 4 + 26 + 12 + 8 +
            (waveDataIN->ckDataPCMShort->dataPCM->data->ck->size / 2);
    waveDataOUT->ckHeader->WAVEID = malloc(sizeof (Chunk));
    strcpy(waveDataOUT->ckHeader->WAVEID, "WAVE");

    // Wave Format Sub-Chunk
    waveDataOUT->ckFormatNonPCM = malloc(sizeof (ChunkFormatNonPCM));
    waveDataOUT->ckFormatNonPCM->format = malloc(sizeof (ChunkFormat));
    waveDataOUT->ckFormatNonPCM->format->ck = malloc(sizeof (Chunk));
    waveDataOUT->ckFormatNonPCM->format->ck->ID = malloc(sizeof (char[5]));
    strcpy(waveDataOUT->ckFormatNonPCM->format->ck->ID, "fmt ");
    waveDataOUT->ckFormatNonPCM->format->ck->size = 18;
    waveDataOUT->ckFormatNonPCM->format->wFormatTag = 0x0006;
    waveDataOUT->ckFormatNonPCM->format->nChannels =
            waveDataIN->ckFormatPCM->format->nChannels;
    waveDataOUT->ckFormatNonPCM->format->nSamplesPerSec =
            waveDataIN->ckFormatPCM->format->nSamplesPerSec;
    waveDataOUT->ckFormatNonPCM->format->nAvgBytesPerSec =
            waveDataIN->ckFormatPCM->format->nAvgBytesPerSec / 2;
    waveDataOUT->ckFormatNonPCM->format->nBlockAlign =
            waveDataIN->ckFormatPCM->format->nBlockAlign / 2;
    waveDataOUT->ckFormatNonPCM->format->wBitsPerSample = 8;
    waveDataOUT->ckFormatNonPCM->cbSize = 0;

    // Wave Fact Sub-Chunk
    waveDataOUT->ckFact = malloc(sizeof (ChunkFact));
    waveDataOUT->ckFact->ck = malloc(sizeof (Chunk));
    waveDataOUT->ckFact->ck->ID = malloc(sizeof (char[5]));
    strcpy(waveDataOUT->ckFact->ck->ID, "fact");
    waveDataOUT->ckFact->ck->size = 4;
    waveDataOUT->ckFact->dwSampleLength =
            waveDataIN->ckDataPCMShort->dataPCM->data->ck->size / 2;

    // Wave Data Sub-Chunk
    waveDataOUT->ckDataNonPCMByte = malloc(sizeof (ChunkDataNonPCMByte));
    waveDataOUT->ckDataNonPCMByte->dataNonPCM = malloc(sizeof (ChunkDataNonPCM));
    waveDataOUT->ckDataNonPCMByte->dataNonPCM->data = malloc(sizeof (ChunkDataNonPCM));
    waveDataOUT->ckDataNonPCMByte->dataNonPCM->data->ck = malloc(sizeof (Chunk));
    waveDataOUT->ckDataNonPCMByte->dataNonPCM->data->ck->ID = malloc(sizeof (char[5]));
    strcpy(waveDataOUT->ckDataNonPCMByte->dataNonPCM->data->ck->ID, "data");
    waveDataOUT->ckDataNonPCMByte->dataNonPCM->data->ck->size =
            waveDataOUT->ckFact->dwSampleLength;
    waveDataOUT->ckDataNonPCMByte->samples = malloc(
            waveDataOUT->ckFact->dwSampleLength * sizeof (char));
    for (i = 0; i < waveDataOUT->ckFact->dwSampleLength; i++) {
        aux = waveDataIN->ckDataPCMShort->samples[i] / 8;
        encode(&(aux), &(waveDataOUT->ckDataNonPCMByte->samples[i]));
    }

    return waveDataOUT;
}

/*
 *
 */
int main(int argc, char** argv) {
    if (argc != 3) {
        fprintf(stderr, "Usage: %s input.wav output.wav\n", argv[0]);
        return (EXIT_FAILURE);
    }
    FILE *file;
    
    // Read PCM S16 LE WAVE file
    file = fopen(argv[1], "rb");
    if (!file) {
        return (EXIT_FAILURE);
    }
    WaveDataPCMShort* waveDataIN = readWaveDataPCMShort(file);
    fclose(file);
    file = fopen(argv[2], "wb");
    if (!file) {
        return (EXIT_FAILURE);
    }

    // Convert samples
    WaveDataNonPCMByte* waveDataOUT = PCMSignedToAlaw(waveDataIN);
    freeWaveDataPCMShort(waveDataIN);

    // Write Non PCM ALAW WAVE file
    writeWaveDataNonPCMByte(waveDataOUT, file);
    freeWaveDataNonPCMByte(waveDataOUT);
    fclose(file);
    
    return (EXIT_SUCCESS);
}